home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
Borland Visual dBASE Professiona v7.0
/
DATA1.CAB
/
Sample_dBASE
/
Calculator.wfm
< prev
next >
Wrap
Text File
|
1997-11-20
|
38KB
|
1,484 lines
//------------------------------------------------------------------------
//
// Calculator.wfm -- Calculator
//
// This file contains a calculator form. This calculator
// contains pushbuttons for numeric input and operations. It
// also contains 2 entryfields -- the main display, showing the
// current calculation, a hidden entry field for storing values
// to memory. Keyboard input is handled through a paintbox control
// that is not visible to the user.
//
// Dependencies: Calculator.ICO
//
// Visual dBASE Samples Group
//
// $Revision: 1.10 $
//
// Copyright (c) 1997, Borland International, Inc.
// All rights reserved.
//
//------------------------------------------------------------------------
//
#define BASE_HEX 16
#define BASE_DEC 10
#define BASE_OCT 8
#define BASE_BIN 2
#define MAX_DIGITS_DEC 18
#define MAX_DIGITS_OCT 16
#define MAX_DIGITS_BIN 16
#define MAX_DIGITS_HEX 8
#define DISPLAY_LEN 18
#define HEX_OVERFLOW 2^32
#define DEC_OVERFLOW 10^18
#define ALLTRIM(x) LTRIM(RTRIM(x))
set talk off
local f
** END HEADER -- do not remove this line
//
// Generated on 11/10/97
//
parameter bModal
local f
f = new CALCULATORFORM()
if (bModal)
f.mdi = false // ensure not MDI
f.readModal()
else
f.open()
endif
class CALCULATORFORM of FORM
with (this)
onGotFocus = class::FORM_ONGOTFOCUS
onClose = class::FORM_ONCLOSE
open = class::FORM_OPEN
scaleFontSize = 8
scaleFontBold = false
colorNormal = "BTNTEXT/BTNFACE"
height = 13.0455
left = 16
top = 3
width = 42.5714
text = "Calculator"
mdi = false
sizeable = false
mousePointer = 1 // Arrow
maximize = false
icon = "FILE Calculator.ico"
endwith
this.RECTANGLE1 = new RECTANGLE(this)
with (this.RECTANGLE1)
left = 1
top = 2.3182
width = 41
height = 1.25
metric = 0 // Chars
text = ""
colorNormal = "WindowText/BtnFace"
fontSize = 8
endwith
this.KEYHANDLER = new PAINTBOX(this)
with (this.KEYHANDLER)
onChar = class::KEYHANDLER_ONCHAR
colorNormal = "BtnFace/BtnFace"
height = 0.5
left = 0.1
top = 0.5
width = 0.1
metric = 0 // Chars
endwith
this.MEMORY = new ENTRYFIELD(this)
with (this.MEMORY)
enabled = false
height = 1
left = 1
top = 11.5
width = 41
metric = 0 // Chars
function = "J"
colorNormal = "BtnText/BtnFace"
colorHighLight = ""
fontSize = 8
value = " "
validRequired = true
borderStyle = 7 // Client
endwith
this.B7 = new PUSHBUTTON(this)
with (this.B7)
onClick = class::DIGIT_ONCLICK
height = 1
left = 1
top = 4
width = 6
text = "7"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B8 = new PUSHBUTTON(this)
with (this.B8)
onClick = class::DIGIT_ONCLICK
height = 1
left = 8
top = 4
width = 6
text = "8"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B9 = new PUSHBUTTON(this)
with (this.B9)
onClick = class::DIGIT_ONCLICK
height = 1
left = 15
top = 4
width = 6
text = "9"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B4 = new PUSHBUTTON(this)
with (this.B4)
onClick = class::DIGIT_ONCLICK
height = 1
left = 1
top = 5.5
width = 6
text = "4"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B5 = new PUSHBUTTON(this)
with (this.B5)
onClick = class::DIGIT_ONCLICK
height = 1
left = 8
top = 5.5
width = 6
text = "5"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B6 = new PUSHBUTTON(this)
with (this.B6)
onClick = class::DIGIT_ONCLICK
height = 1
left = 15
top = 5.5
width = 6
text = "6"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B1 = new PUSHBUTTON(this)
with (this.B1)
onClick = class::DIGIT_ONCLICK
height = 1
left = 1
top = 7
width = 6
text = "1"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B2 = new PUSHBUTTON(this)
with (this.B2)
onClick = class::DIGIT_ONCLICK
height = 1
left = 8
top = 7
width = 6
text = "2"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.B3 = new PUSHBUTTON(this)
with (this.B3)
onClick = class::DIGIT_ONCLICK
height = 1
left = 15
top = 7
width = 6
text = "3"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.OPPLUSMINUS = new PUSHBUTTON(this)
with (this.OPPLUSMINUS)
onClick = class::OPPLUSMINUS_ONCLICK
height = 1
left = 29
top = 7
width = 6
text = "+/-"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "BtnText/BtnFace"
value = false
endwith
this.B0 = new PUSHBUTTON(this)
with (this.B0)
onClick = class::DIGIT_ONCLICK
height = 1
left = 1
top = 8.5
width = 6
text = "0"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.PERIOD = new PUSHBUTTON(this)
with (this.PERIOD)
onClick = class::PERIOD_ONCLICK
height = 1
left = 8
top = 8.5
width = 6
text = ". "
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "B/BtnFace"
value = false
endwith
this.OPPOWER = new PUSHBUTTON(this)
with (this.OPPOWER)
onClick = class::OPCLICK
height = 1
left = 29
top = 5.5
width = 6
text = "^"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "BtnText/BtnFace"
value = false
endwith
this.OPTIMES = new PUSHBUTTON(this)
with (this.OPTIMES)
onClick = class::OPCLICK
height = 1
left = 22
top = 5.5
width = 6
text = "X"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "darkgreen/BtnFace"
value = false
endwith
this.OPDIV = new PUSHBUTTON(this)
with (this.OPDIV)
onClick = class::OPCLICK
height = 1
left = 22
top = 4
width = 6
text = "/"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "darkgreen/BtnFace"
value = false
endwith
this.OPMINUS = new PUSHBUTTON(this)
with (this.OPMINUS)
onClick = class::OPCLICK
height = 1
left = 22
top = 7
width = 6
text = "-"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "darkgreen/BtnFace"
value = false
endwith
this.BUTTONCLEAR = new PUSHBUTTON(this)
with (this.BUTTONCLEAR)
onClick = class::BUTTONCLEAR_ONCLICK
height = 1
left = 29
top = 4
width = 6
text = "CE\C"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "WHITE/RED"
value = false
endwith
this.OPEQUAL = new PUSHBUTTON(this)
with (this.OPEQUAL)
onClick = class::OPCLICK
height = 1
left = 15
top = 8.5
width = 6
text = "="
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Darkgreen/BtnFace"
value = false
endwith
this.OPPLUS = new PUSHBUTTON(this)
with (this.OPPLUS)
onClick = class::OPCLICK
height = 1
left = 22
top = 8.5
width = 6
text = "+"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "darkgreen/BtnFace"
value = false
endwith
this.MADD = new PUSHBUTTON(this)
with (this.MADD)
onClick = class::MEM_ONCLICK
height = 1
left = 36
top = 4
width = 6
text = "M+"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "WHITE/BLUE"
value = false
endwith
this.MSUB = new PUSHBUTTON(this)
with (this.MSUB)
onClick = class::MEM_ONCLICK
height = 1
left = 36
top = 5.5
width = 6
text = "M-"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "WHITE/BLUE"
value = false
endwith
this.MR = new PUSHBUTTON(this)
with (this.MR)
onClick = class::MR_ONCLICK
height = 1
left = 36
top = 7
width = 6
text = "MR"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "WHITE/BLUE"
value = false
endwith
this.MC = new PUSHBUTTON(this)
with (this.MC)
onClick = class::MC_ONCLICK
height = 1
left = 36
top = 8.5
width = 6
text = "MC"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "WHITE/BLUE"
value = false
endwith
this.B_A = new PUSHBUTTON(this)
with (this.B_A)
onClick = class::DIGIT_ONCLICK
height = 1
left = 1
top = 10
width = 6
text = "A"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Blue/BtnFace"
value = false
endwith
this.B_B = new PUSHBUTTON(this)
with (this.B_B)
onClick = class::DIGIT_ONCLICK
height = 1
left = 8
top = 10
width = 6
text = "B"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Blue/BtnFace"
value = false
endwith
this.B_C = new PUSHBUTTON(this)
with (this.B_C)
onClick = class::DIGIT_ONCLICK
height = 1
left = 15
top = 10
width = 6
text = "C"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Blue/BtnFace"
value = false
endwith
this.B_D = new PUSHBUTTON(this)
with (this.B_D)
onClick = class::DIGIT_ONCLICK
height = 1
left = 22
top = 10
width = 6
text = "D"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Blue/BtnFace"
value = false
endwith
this.B_E = new PUSHBUTTON(this)
with (this.B_E)
onClick = class::DIGIT_ONCLICK
height = 1
left = 29
top = 10
width = 6
text = "E"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Blue/BtnFace"
value = false
endwith
this.B_F = new PUSHBUTTON(this)
with (this.B_F)
onClick = class::DIGIT_ONCLICK
height = 1
left = 36
top = 10
width = 6
text = "F"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "Blue/BtnFace"
value = false
endwith
this.DISPLAY = new TEXT(this)
with (this.DISPLAY)
height = 1.6818
left = 6
top = 0.3182
width = 35
border = true
metric = 0 // Chars
colorNormal = "WHITE/BLACK"
marginHorizontal = 0.1905
alignVertical = 1 // Middle
alignHorizontal = 2 // Right
fontName = "Fixedsys"
fontSize = 9
text = "TEXT1"
borderStyle = 5 // Double
endwith
this.RADIOHEX = new RADIOBUTTON(this)
with (this.RADIOHEX)
onGotFocus = {; this.form.KEYHANDLER.setFocus()}
onChange = class::RADIOHEX_ONCHANGE
height = 0.8
left = 3
top = 2.6
width = 7
text = "Hex"
metric = 0 // Chars
colorNormal = "WindowText/BtnFace"
fontSize = 8
tabStop = false
group = true
value = false
endwith
this.RADIODEC = new RADIOBUTTON(this)
with (this.RADIODEC)
onGotFocus = {; this.form.KEYHANDLER.setFocus()}
onChange = class::RADIODEC_ONCHANGE
height = 0.8
left = 14
top = 2.6
width = 7
text = "Dec"
metric = 0 // Chars
colorNormal = "WindowText/BtnFace"
fontSize = 8
tabStop = false
group = false
value = true
endwith
this.RADIOOCT = new RADIOBUTTON(this)
with (this.RADIOOCT)
onGotFocus = {; this.form.KEYHANDLER.setFocus()}
onChange = class::RADIOOCT_ONCHANGE
height = 0.8
left = 24
top = 2.6
width = 7
text = "Oct"
metric = 0 // Chars
colorNormal = "WindowText/BtnFace"
fontSize = 8
tabStop = false
group = false
value = false
endwith
this.RADIOBIN = new RADIOBUTTON(this)
with (this.RADIOBIN)
onGotFocus = {; this.form.KEYHANDLER.setFocus()}
onChange = class::RADIOBIN_ONCHANGE
height = 0.8
left = 34
top = 2.6
width = 7
text = "Bin"
metric = 0 // Chars
colorNormal = "WindowText/BtnFace"
fontSize = 8
tabStop = false
group = false
value = false
endwith
this.OPSQRT = new PUSHBUTTON(this)
with (this.OPSQRT)
onClick = class::OPSQRT_ONCLICK
height = 1
left = 29
top = 8.5
width = 6
text = "sqrt"
metric = 0 // Chars
speedBar = true
fontSize = 8
group = true
colorNormal = "BtnText/BtnFace"
value = false
endwith
this.TEXTMINDICATOR = new TEXT(this)
with (this.TEXTMINDICATOR)
height = 1.7
left = 2
top = 0.3
width = 4
metric = 0 // Chars
colorNormal = "BtnText"
alignVertical = 1 // Middle
text = " "
endwith
function changeBase( newBase )
//
// Change base number system
//
local value, memValue, dispFraction, memFraction
// Get values in display and memory before changing
// hex indicator
value = CLASS::numVal( this.form.display.text )
memValue = CLASS::numVal( this.form.memory.value )
this.form.beforePeriod = true
SET DECIMALS TO this.form.decPlaces
dispFraction = val(substr( this.form.display.text,;
at(this.form.periodChar, this.form.display.text)))
memFraction = val(substr(form.memory.value,;
at(this.form.periodChar, this.form.memory.value)))
this.form.numberSys := newBase
if ( abs(value) >= HEX_OVERFLOW )
// Temporary
this.form.display.text := space(DISPLAY_LEN - MAX_DIGITS_HEX) +;
replicate("*", MAX_DIGITS_HEX)
else
this.form.display.text := CLASS::charVal( value + dispFraction )
endif
if ( abs(memValue) >= HEX_OVERFLOW )
this.form.memory.value := space(DISPLAY_LEN - MAX_DIGITS_HEX) +;
replicate("*", MAX_DIGITS_HEX)
else
this.form.memory.value := CLASS::charVal( memValue + memFraction )
endif
return ( this.form.numberSys )
// {Linked Method} form.b0.onClick
// {Linked Method} form.b3.onClick
// {Linked Method} form.b2.onClick
// {Linked Method} form.b1.onClick
// {Linked Method} form.b6.onClick
// {Linked Method} form.b5.onClick
// {Linked Method} form.b4.onClick
// {Linked Method} form.b9.onClick
// {Linked Method} form.b8.onClick
// {Linked Method} form.b7.onClick
// {Linked Method} form.b_f.onClick
// {Linked Method} form.b_e.onClick
// {Linked Method} form.b_d.onClick
// {Linked Method} form.b_c.onClick
// {Linked Method} form.b_b.onClick
// {Linked Method} form.b_a.onClick
function digit_onClick
return ( class::enterDigit( this.text ) )
// {Linked Method} form.opplusminus.onClick
function OPPLUSMINUS_onClick
//
// Toggle sign of number in display.
//
local num
num = class::NumVal( this.form.display.text )
with ( this.form )
display.text := class::charVal(num * -1)
lastKeyOperator := false
endwith
return ( this.form.display.text )
// {Linked Method} form.opsqrt.onClick
function OPSQRT_onClick
//
// Replace current diplay with square root of display.
//
local num, sText
num = class::NumVal( this.form.display.text )
if ( num < 0 )
this.form.display.text := REPLICATE( "*", MAX_DIGITS_DEC )
else
this.form.display.text := class::CharVal( SQRT( num ) )
endif
this.form.lastKeyOperator := false
return ( this.form.display.text )
function enterDigit( sDigit )
//
// Process a digit.
//
local num
if ( this.form.lastKeyOperator )
with ( this.form )
lastKeyOperator := false
beforePeriod := true
display.text := space(MAX_DIGITS_DEC - 1) +;
class::displayValue( sDigit )
endwith
else
do case
case class::displayFull()
?? chr(7)
case this.form.beforePeriod
// Only want rightmost DISPLAY_LEN characters
this.form.display.text := ;
right( class::displayValue( this.form.display.text ) + ;
class::displayValue( sDigit ), ;
DISPLAY_LEN )
otherwise
this.form.display.text := ;
class::addAfterPeriod( class::displayValue( sDigit ) )
endcase
endif
return ( this.form.display.text )
// {Linked Method} form.opequal.onClick
// {Linked Method} form.optimes.onClick
// {Linked Method} form.oppower.onClick
// {Linked Method} form.opplus.onClick
// {Linked Method} form.opminus.onClick
// {Linked Method} form.opdiv.onClick
function opClick
return ( class::enterOp( this ) )
// {Linked Method} form.period.onClick
function PERIOD_onClick
//
// Process decimal point.
//
if ( this.form.beforePeriod )
with ( this.form )
beforePeriod := false
decPlaces := 1
endwith
set decimals to 1
if ( this.form.lastKeyOperator )
with ( this.form )
lastKeyOperator := false
display.text := ;
space(MAX_DIGITS_DEC - 1) + this.form.periodChar
endwith
else
this.form.display.text := ;
class::AddAfterPeriod( this.form.periodChar )
endif
endif
return ( this.form.display.text )
function enterOp( thisOp )
//
// Process operator.
//
local lastOperation, lastOp, lastValue, tempOpList
if ( this.form.LastKeyOperator or ;
this.form.operationStack.isEmpty() )
this.form.lastValue := class::numVal( this.form.display.text )
else
// Process all previous operations with >= precedence
do while ( this.form.operationStack.prevPrecedenceGreaterOrEqual( ;
thisOp.precedence ) )
lastOperation = this.form.operationStack.pop()
if ( lastOperation.getPrecedence() > 0 ) // Don't process "="
lastOp = lastOperation.getOp()
lastValue = lastOperation.getValue()
set decimals to this.form.mostDecPlaces
this.form.lastValue := ;
lastOp( lastValue, class::numVal( this.form.display.text ) )
this.form.display.text := class::charVal( this.form.lastValue )
this.form.decPlaces := 1
set decimals to 1
endif
enddo
endif
with ( this.form )
beforePeriod := true
lastKeyOperator := true
endwith
thisOp.opValue = class::numVal( this.form.display.text )
this.form.operationStack.push( ( thisOp ) )
return ( thisOp.opValue )
// {Linked Method} form.msub.onClick
// {Linked Method} form.madd.onClick
function mem_onClick
//
// Process a memory action button.
//
local result
result = this.doIt( class::numVal( this.form.memory.value ),;
class::numVal( this.form.display.text ))
with ( this.form )
memory.value := class::CharVal(result)
textMindicator.text := "M"
endwith
return ( result )
// {Linked Method} form.radiobin.onChange
function RADIOBIN_onChange
with ( this.form )
b2.enabled := ( not this.value )
b3.enabled := ( not this.value )
b4.enabled := ( not this.value )
b5.enabled := ( not this.value )
b6.enabled := ( not this.value )
b7.enabled := ( not this.value )
b8.enabled := ( not this.value )
b9.enabled := ( not this.value )
endwith
if ( this.value )
class::changeBase( BASE_BIN )
endif
return ( this.value )
// {Linked Method} form.radiodec.onChange
function RADIODEC_onChange
// Enable keys applicable to decimal calculations
with ( this.form )
opPlusMinus.enabled := ( this.value )
period.enabled := ( this.value )
endwith
if ( this.value )
class::changeBase( BASE_DEC )
endif
return ( this.value )
// {Linked Method} form.radiohex.onChange
function RADIOHEX_onChange
if ( this.value )
this.form.height := 11.5
class::changeBase( BASE_HEX )
else
this.form.height := 10
endif
return ( this.value )
// {Linked Method} form.radiooct.onChange
function RADIOOCT_onChange
with ( this.form )
b8.enabled := ( not this.value )
b9.enabled := ( not this.value )
endwith
if ( this.value )
class::changeBase( BASE_OCT )
endif
return ( this.value )
function displayFull
//
// Check if display already has MAX_DIGITS_DEC digits in it
//
local bFull, maxValueLen
bFull = false
maxValueLen = MAX_DIGITS_DEC
do case
case ( this.form.numberSys == BASE_HEX )
maxValueLen := MAX_DIGITS_HEX
case ( this.form.numberSys == BASE_OCT )
maxValueLen := MAX_DIGITS_OCT
otherwise
maxValueLen := MAX_DIGITS_DEC
endcase
// Check if leftmost digit in current display = " "
bFull := ( not empty( left( right( this.form.display.text, ;
maxValueLen ), 1) ) )
return ( bFull )
function addAfterPeriod(char)
//
// Add fractional digits after decimal point.
//
this.form.decPlaces := this.form.decPlaces + 1
set decimals to this.form.decPlaces
this.form.mostDecPlaces := max( this.form.decPlaces, ;
this.form.mostDecPlaces )
return ( class::DisplayValue( this.form.display.text ) + char )
// {Linked Method} form.buttonclear.onClick
function BUTTONCLEAR_onClick
//
// Set custom form properties to default values
// and clear display..
//
this.form.operationStack.Initialize() // Empty operation stack
set decimals to 1 // Initial decimal places
with ( this.form )
lastValue := 0 // Clear value
lastKeyOperator := null // Clear operators
decPlaces := 1
mostDecPlaces := 1
beforePeriod := true // Start with whole number entry
display.text := SPACE( MAX_DIGITS_DEC - 1 ) + "0"
endwith
return ( this.form.display.text )
function displayValue( value )
//
// Display value without the pick character.
//
local num, pickLoc
num = value
pickLoc = at("&",num)
do case
case ( pickLoc <> 0 )
num := stuff(num,pickLoc,1,"")
case ( right(num,2) = " 0" )
num := space(MAX_DIGITS_DEC)
case ( left(num,1) = SPACE(1) )
num := substr(num,2)
endcase
return ( num )
// {Linked Method} form.onClose
function Form_onClose
//
// Clean up
//
CLOSE PROCEDURE PROGRAM(1)
return ( true )
// {Linked Method} form.onGotFocus
function Form_onGotFocus
//
// Make sure decimal places is correct every time
// this form gets focus.
//
set decimals to this.decPlaces
return ( SET("DECIMALS") )
// {Linked Method} form.keyhandler.onChar
function KEYHANDLER_onChar(nChar, nRepCnt, nFlags)
local sChar, vChar
sChar = UPPER( CHR( nChar ) )
vChar = VAL( sChar )
if ( vChar > 0 AND vChar < this.form.numberSys )
class::enterDigit( sChar )
else
do case
case ( sChar == "0" )
class::enterDigit( sChar )
case ( sChar == "/" )
class::enterOp( this.form.opDiv )
case ( sChar == "*" OR sChar == "X" )
class::enterOp( this.form.opTimes )
case ( sChar == "-" )
class::enterOp( this.form.opMinus )
case ( sChar == "+" )
class::enterOp( this.form.opPlus )
case ( sChar == "^" )
class::enterOp( this.form.opPower )
case ( sChar == "=" OR nChar == 13 )
class::enterOp( this.form.opEqual )
case ( sChar == "." and this.form.period.enabled )
class::period_OnClick()
endcase
endif
return (nChar)
// {Linked Method} form.mc.onClick
function MC_onClick
//
// Memory Clear
//
local thisForm
if ( TYPE("this.form") == "O" )
thisForm = this.form
else
thisForm = this
endif
with ( thisForm )
lastKeyOperator := true
memory.value := space(MAX_DIGITS_DEC - 1) + "0"
textMIndicator.text := null
endwith
return ( thisForm.memory.value )
// {Linked Method} form.mr.onClick
function MR_onClick
//
// Recall from memory.
//
if ( this.form.lastKeyOperator )
with ( this.form )
lastKeyOperator := false
beforePeriod := true
endwith
endif
this.form.lastValue := class::numVal( this.form.display.text )
this.form.display.text := this.form.memory.value
return ( this.form.display.text )
// {Linked Method} form.open
function Form_open
set procedure to program(1) additive
set decimals to 1
this.height := 10 // hide hex
this.periodChar = setto("point") // Set point type for
this.period.text := this.periodChar // current country
this.opPlus.doIt = { |a,b| ; return ( a + b ) }
this.opPlus.precedence = 1
this.opMinus.doIt = { |a,b| ; return ( a - b ) }
this.opMinus.precedence = 1
this.opTimes.doIt = { |a,b| ; return ( a * b ) }
this.opTimes.precedence = 2
this.opDiv.doIt = class::OpDivideIt
this.opDiv.precedence = 2
this.opPower.doIt = { |a,b| ; return ( a ^ b ) }
this.opPower.precedence = 3
this.opEqual.doIt = { |a,b| ; return null }
this.opEqual.precedence = 0
this.mAdd.doIt = { |a,b| ; return ( a + b ) }
this.mAdd.precedence = 1
this.mSub.doIt = { |a,b| ; return ( a - b ) }
this.mSub.precedence = 1
//
// Create custom form properties
//
// Stack for storing operation states
this.operationStack = new OperationStackClass()
this.operationStack.Initialize() // Empty operation stack
this.numberSys = BASE_DEC
this.decPlaces = 1 // Start with minimum decimal places
this.mostDecPlaces = 1 // Most decimal places in an operand
this.beforePeriod = true // Add numbers before or after decimal pt.
this.lastKeyOperator = null
this.lastValue = 0
this.display.text := SPACE( MAX_DIGITS_DEC - 1 ) + "0"
class::MC_onClick()
this.KEYHANDLER.setFocus()
return ( CALCULATORFORM::OPEN() )
function opDivideIt( a, b )
local nResult
nResult = 0
if ( b == 0 )
MSGBOX("Cannot divide by zero.","Alert",48)
else
nResult := ( a / b )
endif
return ( nResult )
function charVal( num )
//
// Convert decimal number to string using
// current base: hex, decimal, octal, binary.
//
local string, fractionVal
local nPlace
local nPValue
string = ""
do case
case ( this.form.numberSys == BASE_HEX )
if ( ABS(num) >= HEX_OVERFLOW )
string := replicate("*", MAX_DIGITS_HEX)
else
string := itoh(num)
string := space(MAX_DIGITS_DEC - len(string)) + string
endif
case ( this.form.numberSys == BASE_OCT )
string := class::toBaseString( num, 16, BASE_OCT )
case ( this.form.numberSys == BASE_BIN )
string := class::toBaseString( num, 16, BASE_BIN )
case ( this.form.numberSys == BASE_DEC )
if ( ABS(num) >= DEC_OVERFLOW )
string := replicate("*", MAX_DIGITS_DEC)
else
string := str(num, MAX_DIGITS_DEC, this.form.decPlaces)
if ( VAL(right(string, this.form.decPlaces)) == 0 ) // If fraction = 0
string := str(num, MAX_DIGITS_DEC)
endif
endif
endcase
return ( string )
function toBaseString( nDecValue, nMaxPlace, nBase )
local nPlace
local npValue
local nAdd
local sValue
local bStart
local bCarry
nPlace = nMaxPlace
npValue = 0
sValue = ""
bStart = false
if ( ABS( nDecValue ) >= nBase ^ nPlace )
sValue = REPLICATE("*", nMaxPlace )
else
do while ( nPlace >= 0 )
if ( nDecValue == 0 )
sValue := sValue + "0"
else
npValue := ( nBase ^ nPlace )
if ( ( npValue <= nDecValue ) or ;
( npValue == 1 ) )
bStart := true
if ( nDecValue / npValue ) == nBase
sValue := sValue + "10"
else
sValue := sValue + ;
ALLTRIM( STR( INT( nDecValue / npValue ) ) )
endif
nDecValue := MOD( nDecValue, npValue )
else
if ( bStart )
sValue := sValue + "0"
endif
endif
endif
nPlace := nPlace - 1
enddo
if ( VAL( sValue ) == 0 )
sValue := "0"
endif
sValue := SPACE( MAX_DIGITS_DEC - LEN( sValue ) ) + sValue
endif
return ( sValue )
function numVal( string )
//
// Return decimal value of display value using
// current base to translate.
//
local h, num, nPeriod
local sValue
local nDigit, nPlace
private macro
sValue = ALLTRIM( string )
h = ""
macro = ""
num = 0
nDigit = 0
nPlace = 0
nPeriod = 0
do case
case ( this.form.numberSys == BASE_HEX )
h := htoi(string)
num := iif(h >= HEX_OVERFLOW/2, bitxor(h, HEX_OVERFLOW), h)
case ( this.form.numberSys == BASE_OCT )
if ( sValue == null )
num := 0
else
if ( SUBSTR( sValue, 1, 1 ) == "*" )
num := ( 1 / 0 )
else
macro := "0" + sValue
num := ¯o.
endif
endif
case ( this.form.numberSys == BASE_BIN )
do while ( LEN( sValue ) > 0 )
nDigit := IIF( RIGHT( sValue, 1 ) == "1", 1, 0 )
sValue := SUBSTR( sValue, 1, ( LEN( sValue ) - 1 ) )
num := num + ( nDigit * (2 ^ nPlace) )
nPlace := nPlace + 1
enddo
otherwise
// decimal
nPeriod := AT( this.form.periodChar, sValue )
if ( nPeriod <> 0 )
num := VAL( STUFF( sValue, nPeriod, 1, "." ) )
else
num := VAL( sValue )
endif
endcase
return ( num )
endclass
class OperationStackClass
//
// This class defines a stack object for storing
// mathematical operation states. This is necessary
// for using operators that have different precedence, like
// + and *. This is a stack of OperationStateClass objects.
//
class::initialize()
function initialize
//
// Create empty stack
//
// Bottom (and top, at first) of Stack
this.stackTop = new OperationStateClass()
return true
function isEmpty
//
// Check if stack is empty
//
return empty( this.stackTop.getNext() ) // Empty if no more operations
function pop
//
// Retrieve last operation state
//
local xOp
xOp = false
if ( empty(this.stackTop.getNext()) )
InformationMessage("ERROR: Trying to pop empty stack", "Info")
else
xOp := this.stackTop
this.stackTop = this.stackTop.getNext()
endif
return xOp
function push( operation )
//
// Save last operation state
//
local newStackTop
newStackTop = new operationStateClass() // Create new operationState
newStackTop.assign( operation ) // Assign to it properties of
// operation
newStackTop.setNext( this.stackTop ) // Make current top be next
this.stackTop = newStackTop // Make new operation be top
return true
function prevPrecedenceGreaterOrEqual(curPrecedence)
//
// Retrieve last operation state
//
return ( this.stackTop.getPrecedence() >= curPrecedence )
endclass
class OperationStateClass
//
// This class defines a single operation state, which is to
// be stored on the operationStack
//
this.op = { |a,b| ; return null }
this.precedence = -1
this.opValue = 0
this.next = false
function getOp
return ( this.op )
function setOp( newOp )
this.op := newOp
return ( this.op )
function getPrecedence
return ( this.precedence )
function setPrecedence( newPrecedence )
this.precedence := newPrecedence
return ( this.precedence )
function getValue
return ( this.opValue )
function setValue( newValue )
this.opValue := newValue
return ( this.opValue )
function getNext
return ( this.next )
function setNext(newNext)
this.next := newNext
return ( this.next )
function assign( newOperationState )
with ( this )
op := newOperationState.doIt
precedence := newOperationState.precedence
opValue := newOperationState.opValue
endwith
return ( this.opValue )
endclass